#!/usr/bin/python
# -*- coding: utf8 -*-

from pyparsing import ParserElement, Literal, StringEnd
from expresion import TipoExp, Exp

from sets import Set


#############################################
# Clase Extension                           #
#############################################

class Extension(object):
    def __init__(self, nombre, expresiones=None, tipos=None):
        """
        Construye un objeto Extension que representa un conjunto
        de expresiones y tipos que conforman una extensión al cálculo
        lambda.
        
        Recibe un nombre (identificador) de la extensión, y dos
        conjuntos de expresiones y tipos (instancias de Expresion y Type
        respectivamente).
        """
        
        self.nombre = nombre
        
        if expresiones != None:
            self.expresiones = Set(expresiones)
        else:
            self.expresiones = Set()

        if tipos != None:
            self.tipos = Set(tipos)
        else:
            self.tipos = Set()
    
    def __repr__(self):
        return "<Extension %s>" % self.nombre


#############################################
# Clase Lenguaje                            #
#############################################

# optimización para el parser
ParserElement.enablePackrat()

class Lenguaje:
    def __init__(self, extensiones):
        """
        Construye un objeto Lenguaje que representa un posible
        lenguaje (extendido) dentro del cálculo lambda.
        
        Recibe un conjunto de extensiones (no vacío).
        """
        if len(extensiones) == 0:
            raise ValueError("Un lenguaje debe tener al menos una extensión!")
        
        TipoAux = Literal('(').suppress() + TipoExp + Literal(')').suppress()
        ExpAux = Literal('(').suppress() + Exp + Literal(')').suppress()
        
        for ext in extensiones:
            for t1 in ext.tipos:

                TipoAux = TipoAux ^ (t1.sintaxis().setParseAction(t1.parseAction))
            
            for e in ext.expresiones:
                e1 = e.sintaxis()
                e1.setParseAction(e.parseAction)
                ExpAux = ExpAux ^ e1
        
        TipoExp << TipoAux
        Exp << ExpAux
        self.Prog = Exp + StringEnd()
    
    def parseFile(self, f):
        return self.Prog.parseFile(f)[0]

    def parseString(self, s):
        return self.Prog.parseString(s)[0]

